package ynu.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import ynu.edu.domain.HanziGenerationRequest;
import ynu.edu.domain.HanziGenerationResponse;
import ynu.edu.domain.PageDTO;
import ynu.edu.entity.HanziGeneration;
import ynu.edu.mapper.HanziGenerationMapper;
import ynu.edu.service.HanziGenerationService;
import ynu.edu.utils.AliOssUtil;

import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 汉字生成记录Service实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HanziGenerationServiceImpl extends ServiceImpl<HanziGenerationMapper, HanziGeneration> implements HanziGenerationService {

    private final RestTemplate restTemplate;
    private final AliOssUtil aliOssUtil;

    @Value("${flask.hanzi.generation.url:http://127.0.0.1:5000/api/generate}")
    private String flaskGenerateUrl;

    @Value("${oss.hanzi.path:hanzi/}")
    private String ossPath;

    @Override
    public HanziGenerationResponse createGenerationRecord(HanziGenerationRequest request) {
        long startTime = System.currentTimeMillis();
        
        // 1. 创建初始记录
        HanziGeneration entity = new HanziGeneration();
        entity.setChineseChar(request.getChineseChar());
        entity.setSteps(request.getSteps());
        entity.setStatus(HanziGeneration.Status.PROCESSING.getCode());
        entity.setRequestId(request.getRequestId() != null ? request.getRequestId() : generateRequestId());
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        
        // 保存到数据库
        save(entity);
        log.info("创建汉字生成记录成功，ID: {}, 汉字: {}, 请求ID: {}", 
                entity.getId(), entity.getChineseChar(), entity.getRequestId());

        try {
            // 2. 调用Flask服务生成汉字图片
            byte[] imageData = callFlaskService(entity.getChineseChar(), entity.getSteps());
            
            // 3. 上传到OSS
            String ossUrl = uploadToOss(imageData, entity.getChineseChar(), entity.getRequestId());
            
            // 4. 计算生成耗时
            long generationTime = System.currentTimeMillis() - startTime;
            
            // 5. 更新记录状态为成功
            entity.setStatus(HanziGeneration.Status.SUCCESS.getCode());
            entity.setOssUrl(ossUrl);
            entity.setGenerationTime(generationTime);
            entity.setUpdateTime(LocalDateTime.now());
            
            updateById(entity);
            
            log.info("汉字生成完成，ID: {}, 耗时: {}ms",
                    entity.getId(), generationTime);
            
        } catch (Exception e) {
            // 6. 如果失败，更新记录状态为失败
            long generationTime = System.currentTimeMillis() - startTime;
            entity.setStatus(HanziGeneration.Status.FAILED.getCode());
            entity.setErrorMessage(e.getMessage());
            entity.setGenerationTime(generationTime);
            entity.setUpdateTime(LocalDateTime.now());
            
            updateById(entity);
            
            log.error("汉字生成失败，ID: {}, 错误: {}", entity.getId(), e.getMessage(), e);
            throw new RuntimeException("汉字生成失败: " + e.getMessage(), e);
        }
        
        return HanziGenerationResponse.fromEntity(entity);
    }

    /**
     * 调用Flask服务生成汉字图片
     */
    private byte[] callFlaskService(String chineseChar, Integer steps) {
        try {
            // 构建请求参数
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("char", chineseChar);
            requestBody.put("steps", steps);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);

            // 创建请求实体
            HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);

            log.info("调用Flask服务生成汉字: {}, 步数: {}, URL: {}", chineseChar, steps, flaskGenerateUrl);

            // 发送POST请求到Flask服务
            ResponseEntity<Map> response = restTemplate.exchange(
                    flaskGenerateUrl,
                    HttpMethod.POST,
                    requestEntity,
                    Map.class
            );

            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                
                // 检查响应状态
                if (!"success".equals(responseBody.get("status"))) {
                    throw new RuntimeException("Flask服务返回错误状态: " + responseBody.get("error"));
                }
                
                // 提取base64编码的图片
                String base64Image = (String) responseBody.get("image");
                if (base64Image == null || base64Image.trim().isEmpty()) {
                    throw new RuntimeException("Flask服务返回的图片数据为空");
                }
                
                // 解码base64图片数据
                byte[] imageData = Base64.getDecoder().decode(base64Image);
                
                log.info("Flask服务调用成功，返回图片大小: {} bytes", imageData.length);
                return imageData;
            } else {
                throw new RuntimeException("Flask服务返回错误状态: " + response.getStatusCode());
            }

        } catch (Exception e) {
            log.error("调用Flask服务失败: {}", e.getMessage(), e);
            throw new RuntimeException("调用Flask服务失败: " + e.getMessage(), e);
        }
    }

    /**
     * 上传图片到OSS
     */
    private String uploadToOss(byte[] imageData, String chineseChar, String requestId) {
        try {
            // 生成OSS文件名
            String fileName = generateOssFileName(chineseChar, requestId);
            String ossKey = ossPath + fileName;

            log.info("开始上传图片到OSS，文件名: {}, OSS Key: {}", fileName, ossKey);

            // 使用AliOssUtil上传
            String ossUrl = aliOssUtil.upload(imageData, ossKey);

            return ossUrl;

        } catch (Exception e) {
            log.error("上传OSS失败: {}", e.getMessage(), e);
            throw new RuntimeException("上传OSS失败: " + e.getMessage(), e);
        }
    }

    /**
     * 生成OSS文件名
     */
    private String generateOssFileName(String chineseChar, String requestId) {
        String timestamp = LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        return String.format("%s_%s_%s.png", chineseChar, timestamp, requestId);
    }

    /**
     * 生成请求ID
     */
    private String generateRequestId() {
        return "hanzi_" + UUID.randomUUID().toString().replace("-", "").substring(0, 8);
    }

    @Override
    public boolean updateStatus(Long id, String status, String ossUrl, Long generationTime, String errorMessage) {
        HanziGeneration entity = getById(id);
        if (entity == null) {
            return false;
        }
        
        entity.setStatus(status);
        entity.setOssUrl(ossUrl);
        entity.setGenerationTime(generationTime);
        entity.setErrorMessage(errorMessage);
        entity.setUpdateTime(LocalDateTime.now());
        
        return updateById(entity);
    }

    @Override
    public List<HanziGenerationResponse> findByChineseChar(String chineseChar) {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getChineseChar, chineseChar)
               .orderByDesc(HanziGeneration::getCreateTime);
        
        List<HanziGeneration> entities = list(wrapper);
        return entities.stream()
                .map(HanziGenerationResponse::fromEntity)
                .collect(Collectors.toList());
    }

    @Override
    public List<HanziGenerationResponse> findByStatus(String status) {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getStatus, status)
               .orderByDesc(HanziGeneration::getCreateTime);
        
        List<HanziGeneration> entities = list(wrapper);
        return entities.stream()
                .map(HanziGenerationResponse::fromEntity)
                .collect(Collectors.toList());
    }

    @Override
    public HanziGenerationResponse findByRequestId(String requestId) {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getRequestId, requestId);
        
        HanziGeneration entity = getOne(wrapper);
        return HanziGenerationResponse.fromEntity(entity);
    }

    @Override
    public PageDTO<HanziGeneration> getPage(int page, int size) {
        Page<HanziGeneration> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(HanziGeneration::getCreateTime);
        
        Page<HanziGeneration> result = page(pageParam, wrapper);
        return PageDTO.of(result, HanziGeneration.class);
    }

    @Override
    public long countRecords() {
        return count();
    }

    @Override
    public long countSuccessRecords() {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getStatus, HanziGeneration.Status.SUCCESS.getCode());
        return count(wrapper);
    }

    @Override
    public long countFailedRecords() {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getStatus, HanziGeneration.Status.FAILED.getCode());
        return count(wrapper);
    }

    @Override
    public long countProcessingRecords() {
        LambdaQueryWrapper<HanziGeneration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(HanziGeneration::getStatus, HanziGeneration.Status.PROCESSING.getCode());
        return count(wrapper);
    }
} 